/*!
 * \file sap_core.c
 *
 * \brief SAP数据包解析
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 *
 * \version 2.0
 * \author wuwk
 * \date 2016/08/24
 *
 */
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>

#include "frservice_comm.h"
#include "sap_core.h"
#include "sap_analysis.h"
#include "config.h"


extern void *g_p_apm_context;

/*!
 * 释放分片包信息
 *
 * \param *p_st_fragment        (L7_fragment_sap  分片包信息)
 *
 * \return
 *
 */
FR_STATIC void __sap_init_fragment(L7_fragment_sap *p_st_fragment)
{
    if (p_st_fragment == NULL)
        return;

    if (p_st_fragment->p_st_data)
       bytebuff_free(&p_st_fragment->p_st_data);

    p_st_fragment->u64_total_len = 0;
    p_st_fragment->u64_left_len = 0;

    return;
}

/*!
 * 初始化session信息
 *
 * \param *p_st_session        (L7_session  session信息)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __sap_init_private(L7_session *p_st_session)
{
    L7session_sap_private *p_st_private_session = NULL;
    L7_fragment_sap *p_st_fragment = NULL;
    L7Session_sap *p_st_l7_session = NULL;

    // 申请整个私有session结构的内存
    p_st_private_session = (L7session_sap_private *)frmalloc(sizeof(L7session_sap_private));
    if (p_st_private_session == NULL)
        return FR_FAIL;

    memset(p_st_private_session, 0x00, sizeof(L7session_sap_private));

    // 申请分片包结构内存
    p_st_fragment = (L7_fragment_sap *)frmalloc(sizeof(L7_fragment_sap));
    if (p_st_fragment == NULL)
    {
        frfree(p_st_private_session);
        return FR_FAIL;
    }
    memset(p_st_fragment, 0x00, sizeof(L7_fragment_sap));

    // 申请session结构体内存
    p_st_l7_session = (L7Session_sap *)frmalloc(sizeof(L7Session_sap));
    if (p_st_l7_session == NULL)
    {
        frfree(p_st_private_session);
        frfree(p_st_fragment);
        return FR_FAIL;
    }
    memset(p_st_l7_session, 0x00, sizeof(L7Session_sap));

    p_st_private_session->p_st_fragment = p_st_fragment;
    p_st_private_session->p_st_l7_session = p_st_l7_session;

    p_st_session->p_session_private = p_st_private_session;

    return FR_SUCC;
}

/*!
 * 释放解析完的数据和分片包
 *
 * \param *p_st_private        (L7session_sap_private  sap私有数据)
 *
 * \return
 *
 */
FR_STATIC void __sap_reset_private(L7session_sap_private *p_st_private)
{
    if (p_st_private == NULL)
        return;

    __sap_init_fragment(p_st_private->p_st_fragment);

    if (p_st_private->p_st_head)
    {
        frfree(p_st_private->p_st_head);
        p_st_private->p_st_head = NULL;
    }

    if (p_st_private->p_st_l7_session && p_st_private->p_st_l7_session->p_title)
    {
        frfree(p_st_private->p_st_l7_session->p_title);
        p_st_private->p_st_l7_session->p_title = NULL;
    }

    memset(&(p_st_private->st_trans_info.st_l4_trans), 0x00, sizeof(L4_transaction));

    bytebuff_free(&p_st_private->p_st_uncompress_data);
    frreport_body_free(&p_st_private->p_st_data_req);
    frreport_body_free(&p_st_private->p_st_data_resp);

    frreport_body_l7list_free(&p_st_private->p_lst_req);

    return;
}

/*!
 * 释放解析完的数据
 *
 * \param *p_st_private        (L7session_sap_private  sap私有数据)
 *
 * \return
 *
 */
//FR_STATIC void __sap_reset_analysis_data(L7session_sap_private *p_st_private)
//{
//    L7_fragment_sap *p_st_fragment = NULL;
//    L4_transaction *p_st_l4_trans = NULL;
//
//    if (p_st_private == NULL || p_st_private->p_st_fragment == NULL)
//        return;
//
//    p_st_fragment = p_st_private->p_st_fragment;
//    bytebuff_rewind(p_st_fragment->p_st_data);
//
//    // 大数据处理：不清空收包接收时间
//    p_st_l4_trans = &(p_st_private->st_trans_info.st_l4_trans);
//    if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0)
//    {
//        p_st_l4_trans->st_request_time.tv_sec = 0;
//        p_st_l4_trans->st_request_time.tv_usec = 0;
//    }
//    p_st_l4_trans->st_response_time.tv_sec = 0;
//    p_st_l4_trans->st_response_time.tv_usec = 0;
//
//    frreport_body_free(&p_st_private->p_st_data_req);
//    frreport_body_free(&p_st_private->p_st_data_resp);
//
//    return;
//}

/*!
 * 取数据包长度
 *
 * \param *p_data        (char  数据)
 *
 * \return 长度
 *
 */
FR_STATIC unsigned int __sap_get_packet_len(char *p_data)
{
    char arr_len[5];
    uint32_t *p_u32_len = 0;
    unsigned int ui_len = 0;

    memcpy(arr_len, p_data, 4);
    arr_len[4] = '\0';
    p_u32_len = (uint32_t *)arr_len;
    ui_len = ntohl(*p_u32_len);

    return ui_len;
}

/*!
 * sap数据上报
 *
 * \param *p_st_private        (L7session_sap_private  sap私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
 * \param *i_req_resp          (int     请求/响应)
 *
 * \return FR_SUCC:成功\n
 *         FR_FAIL:失败\n
 *
 */
FR_STATIC int __sap_data_report(L7session_sap_private *p_st_private
                              , Conntrack *p_st_conn
                              , Frreport_body_data *p_st_body_data
                              , Frhash_header *p_st_hash_report
                              , int i_req_resp)
{
    Frreport_data *p_st_report_data = NULL;
    L7_head_sap *p_st_head = NULL;
    L4_transaction *p_st_l4_trans = NULL;

    if (p_st_private == NULL || p_st_private->p_st_head == NULL
        || p_st_conn == NULL || p_st_body_data == NULL || p_st_hash_report == NULL)
        return FR_FAIL;

    p_st_head = p_st_private->p_st_head;

    p_st_l4_trans = &(p_st_private->st_trans_info.st_l4_trans);

    if (p_st_private->p_st_l7_session != NULL || p_st_private->p_st_l7_session->p_title != NULL)
    {
        if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_st_private->p_st_l7_session->p_title) == FR_FAIL)
            return FR_FAIL;
    }

    // request数据上报
    if (i_req_resp == SAP_REQUEST)
    {
        // 保存request数据
        p_st_private->p_lst_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_private->p_st_data_req);
        if (p_st_private->p_lst_req == NULL)
            goto err;

        // 数据上报
        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
        if (p_st_report_data == NULL)
            goto err;

        if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_data_req) == FR_FAIL)
            goto err;

        if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto err;
        p_st_private->p_st_data_req = NULL;
    }
    else  // response数据上报
    {
        // 数据上报
        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
        if (p_st_report_data == NULL)
            goto err;

        if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_data_resp) == FR_FAIL)
            goto err;

        if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto err;
        p_st_private->p_st_data_resp = NULL;
    }
    p_st_report_data = NULL;

    return FR_SUCC;

err:
    if (p_st_private->p_lst_req)
        frreport_body_l7list_free(&p_st_private->p_lst_req);
    if (p_st_private->p_st_data_req)
        frreport_body_free(&p_st_private->p_st_data_req);
    if (p_st_private->p_st_data_resp)
        frreport_body_free(&p_st_private->p_st_data_resp);
    frreport_data_free(&p_st_report_data);

    return FR_FAIL;
}

/*!
 * sap请求解析
 *
 * \param *p_st_private        (L7session_sap_private  sap私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
 * \param *p_st_packet         (Apm_packet    数据包信息)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *
 */
FR_STATIC int __sap_req_analysis(L7session_sap_private *p_st_private
                               , Conntrack *p_st_conn
                               , Frhash_header *p_st_hash_report
                               , Apm_packet *p_st_packet)
{
    int i_ret = 0;
    unsigned long ul_time_diff = 0;
    L4_transaction *p_st_l4_trans = NULL;
    L7_fragment_sap *p_st_fragment = NULL;

    if (p_st_private == NULL || p_st_private->p_st_fragment == NULL
        || p_st_conn == NULL || p_st_hash_report == NULL || p_st_packet == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    p_st_fragment = p_st_private->p_st_fragment;
    p_st_l4_trans = &(p_st_private->st_trans_info.st_l4_trans);

    if (frlist_empty(p_st_private->p_lst_req) == FR_NO)
    {
        frreport_body_l7list_free(&p_st_private->p_lst_req);
        if (p_st_private->p_st_data_req)
            frreport_body_free(&p_st_private->p_st_data_req);
        memset(p_st_l4_trans, 0x00, sizeof(L4_transaction));
    }

    if (p_st_private->p_st_data_req == NULL)
    {
        p_st_private->p_st_data_req = frreport_body_new_l7(p_st_conn);
        if (p_st_private->p_st_data_req == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    if (p_st_l4_trans->st_request_time_first_byte.tv_sec == 0
        && p_st_l4_trans->st_request_time_first_byte.tv_usec == 0)
    {
        // 请求发起的第一个数据包时间
        p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

        p_st_private->ul_seq = frct_seq_increase(p_st_conn);
    }

    if (frreport_body_l7_add_connInfo(p_st_private->p_st_data_req, p_st_conn) == FR_FAIL)
        goto err;

    if (frreport_body_l7_add_ulong(p_st_private->p_st_data_req, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
        goto err;

    if (frreport_body_l7_add_timeval(p_st_private->p_st_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_l4_trans->st_request_time_first_byte) == FR_FAIL)
        goto err;

    // 请求结束时间
    p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    if (frreport_body_l7_add_timeval(p_st_private->p_st_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
        goto err;

    // 请求发送时间
    ul_time_diff = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_l4_trans->st_request_time));
    if (frreport_body_l7_add_ulong(p_st_private->p_st_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_time_diff) == FR_FAIL)
        goto err;

    // 请求的字节数
    p_st_l4_trans->l_request_bytes = p_st_fragment->u64_total_len;
    if (frreport_body_l7_add_long(p_st_private->p_st_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_fragment->u64_total_len) == FR_FAIL)
        goto err;

    // SAP体部数据解析
    i_ret = sap_analysis_body(p_st_conn, p_st_packet, p_st_fragment->p_st_data, p_st_private->p_st_data_req, p_st_private, SAP_REQUEST);
    if (i_ret == FR_SUCC)
    {
        // 数据上报
        i_ret = __sap_data_report(p_st_private, p_st_conn, p_st_private->p_st_data_req, p_st_hash_report, SAP_REQUEST);
        if (i_ret == FR_FAIL)
            goto err;

        if (p_st_private->p_st_uncompress_data)
            bytebuff_free(&p_st_private->p_st_uncompress_data);

        return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
    }

err:
    if (p_st_private->p_st_data_req)
        frreport_body_free(&p_st_private->p_st_data_req);

    if (p_st_private->p_st_uncompress_data)
        bytebuff_free(&p_st_private->p_st_uncompress_data);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * sap响应解析
 *
 * \param *p_st_private        (L7session_sap_private  sap私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
 * \param *p_st_packet         (Apm_packet    数据包信息)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *
 */
FR_STATIC int __sap_resp_analysis(L7session_sap_private *p_st_private
                                , Conntrack *p_st_conn
                                , Frhash_header *p_st_hash_report
                                , Apm_packet *p_st_packet)
{
    int i_ret = 0;
    L4_transaction *p_st_l4_trans = NULL;
    L7_fragment_sap *p_st_fragment = p_st_private->p_st_fragment;
    unsigned long ul_time_diff = 0;

    if (p_st_private == NULL || p_st_private->p_st_fragment == NULL
        || p_st_conn == NULL || p_st_hash_report == NULL || p_st_packet == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    p_st_fragment = p_st_private->p_st_fragment;
    p_st_l4_trans = &(p_st_private->st_trans_info.st_l4_trans);

    if (p_st_private->p_st_data_resp == NULL)
    {
        p_st_private->p_st_data_resp = frreport_body_new_l7(p_st_conn);
        if (p_st_private->p_st_data_resp == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0
        && p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
    {
        // 响应发起的第一个数据包时间
        p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;
    }

    i_ret = frreport_body_l7_add_connInfo(p_st_private->p_st_data_resp, p_st_conn);
    if (i_ret == FR_FAIL)
        goto err;

    // 有request
    if (p_st_l4_trans->st_request_time.tv_sec != 0 && p_st_private->p_lst_req != NULL)
    {
        if (FRREPORT_BODY_L7LIST_SET_REQ(p_st_private->p_st_data_resp, &p_st_private->p_lst_req) == FR_FAIL)
            goto err;

        ul_time_diff = frtime_diff(&(p_st_l4_trans->st_request_time), &p_st_packet->st_timestamp);
        if (frreport_body_l7_add_ulong(p_st_private->p_st_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_time_diff) == FR_FAIL)
            goto err;
    }

    if (frreport_body_l7_add_timeval(p_st_private->p_st_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_l4_trans->st_response_time_first_byte) == FR_FAIL)
        goto err;

    // 结束时间
    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
    if (frreport_body_l7_add_timeval(p_st_private->p_st_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
        goto err;

    // 下载时间
    ul_time_diff = frtime_diff(&(p_st_l4_trans->st_response_time_first_byte), &p_st_packet->st_timestamp);
    if (frreport_body_l7_add_ulong(p_st_private->p_st_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_time_diff) == FR_FAIL)
        goto err;

    // 响应的字节数
    p_st_l4_trans->l_response_bytes = p_st_fragment->u64_total_len;
    if (frreport_body_l7_add_long(p_st_private->p_st_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_fragment->u64_total_len) == FR_FAIL)
        goto err;

    // SAP体部数据解析
    i_ret = sap_analysis_body(p_st_conn, p_st_packet, p_st_fragment->p_st_data, p_st_private->p_st_data_resp, p_st_private, SAP_RESPONSE);
    if (i_ret == FR_SUCC)
    {
        // 数据上报
        i_ret = __sap_data_report(p_st_private, p_st_conn, p_st_private->p_st_data_resp, p_st_hash_report, SAP_RESPONSE);
        if (i_ret == FR_FAIL)
            return APM_L7_ANALYZE_FAIL;

        __sap_reset_private(p_st_private);

        return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
    }

err:
    if (p_st_private->p_st_data_resp)
        frreport_body_free(&p_st_private->p_st_data_resp);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * sap体部解析
 *
 * \param *p_st_private        (L7session_sap_private  sap私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
 * \param *p_st_packet         (Apm_packet    数据包信息)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *
 */
FR_STATIC int __sap_analysis_data(L7session_sap_private *p_st_private
                                , Conntrack *p_st_conn
                                , Frhash_header *p_st_hash_report
                                , Apm_packet *p_st_packet)
{
    int i_ret = 0;
    L7_head_sap *p_st_head = NULL;

    if (p_st_private == NULL || p_st_private->p_st_head == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_head = p_st_private->p_st_head;

    // request
    if (p_st_head->i_isreq == 1)
    {
        i_ret = __sap_req_analysis(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
    }
    else
    {
        i_ret = __sap_resp_analysis(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
    }

    return i_ret;
}

/*!
 * sap packet解析
 *
 * \param *p_st_private        (L7session_sap_private  sap私有数据)
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
 * \param *p_st_packet         (Apm_packet    数据包信息)
 * \param *p_data              (char                  数据包数据)
 * \param ui_data_len          (unsigned int      数据包数据长度)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *         APM_L7_ANALYZE_TODO:数据包不完整
 *
 */
FR_STATIC int __sap_getdata_analysis(L7session_sap_private *p_st_private
                                   , Conntrack *p_st_conn
                                   , Frhash_header *p_st_hash_report
                                   , Apm_packet *p_st_packet
                                   , char *p_data
                                   , unsigned int ui_data_len)
{
    L7_fragment_sap *p_st_fragment = NULL;
    L7_head_sap *p_st_head = NULL;
    char arr_flag[2];
    unsigned int ui_left_len = 0;
    unsigned int ui_len = 0;
    int i_ret = 0;

    if (p_st_private == NULL || p_st_private->p_st_fragment == NULL
        || p_st_packet == NULL || p_st_packet->p_payload == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_fragment = p_st_private->p_st_fragment;
    if (ui_data_len == 0)
        return APM_L7_ANALYZE_TODO;

    // 创建bytebuffer
    if (p_st_fragment->p_st_data == NULL)
    {
        // 做成bytebuffer
        p_st_fragment->p_st_data = bytebuff_creat();
        if (p_st_fragment->p_st_data == NULL)
            goto err;
    }

    // 上次packet还遗留的数据长度
    ui_left_len = p_st_fragment->u64_left_len;

    // 上次的数据包不完整
    if (ui_left_len)
    {
        memset(arr_flag, 0x00, sizeof(arr_flag));
        // 本次数据还不够
        if (ui_left_len > ui_data_len)
        {
            // 将本次数据存入buffer
            i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_data_len);
            if (i_ret != FR_SUCC)
                goto err;
            p_st_fragment->u64_left_len -= ui_data_len;

            if (bytebuff_remaining(p_st_fragment->p_st_data) >= 12)
            {
                if (bytebuff_get_bytes_at(p_st_fragment->p_st_data, 11, 1, arr_flag) == FR_FAIL)
                    goto err;

                // 如果是压缩过的数据，必须要全部接收完再解析
                if (strcmp(arr_flag, "\x01") == 0)
                    return APM_L7_ANALYZE_TODO;
            }
            else
                return APM_L7_ANALYZE_TODO;
        }
        else
        {
            // 将剩余需要的数据存入buffer
            i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_left_len);
            if (i_ret != FR_SUCC)
                goto err;
            p_st_fragment->u64_left_len = 0;
        }

        if (p_st_fragment->p_st_data->ui_skip_len != 0)
            return APM_L7_ANALYZE_TODO;

        ui_len = __sap_get_packet_len(p_data);
        // 解析头部数据
        i_ret = sap_analysis_head(p_st_fragment->p_st_data, ui_len, &p_st_head);
        if (i_ret != FR_SUCC)
            goto err;

        if (p_st_private->p_st_head)
            frfree(p_st_private->p_st_head);
        p_st_private->p_st_head = p_st_head;
        p_st_fragment->u64_total_len = p_st_head->ul_packet_len;

        // 解析当前体数据
        i_ret = __sap_analysis_data(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto err;
        else if (i_ret == APM_L7_ANALYZE_TODO)
        {
            frfree(p_st_private->p_st_head);
            p_st_private->p_st_head = NULL;
            return APM_L7_ANALYZE_TODO;
        }
        else
        {
            frfree(p_st_private->p_st_head);
            p_st_private->p_st_head = NULL;
            if (p_st_fragment->p_st_data)
                bytebuff_free(&p_st_fragment->p_st_data);
            p_st_fragment->u64_total_len = 0;

            return i_ret;
        }
    }

    // 上次的数据包完整，开始新的数据包解析
    // 取前4位长度
    if (ui_data_len <= 4)
        goto err;

    ui_len = __sap_get_packet_len(p_data);
    // 数据长度不够
    if (ui_len > ui_data_len - 4)
    {
        i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_data_len);
        if (i_ret != FR_SUCC)
            goto err;

        p_st_fragment->u64_left_len = ui_len - (ui_data_len - 4);
        if (bytebuff_remaining(p_st_fragment->p_st_data) >= 12)
        {
            memset(arr_flag, 0x00, sizeof(arr_flag));
            if (bytebuff_get_bytes_at(p_st_fragment->p_st_data, 11, 1, arr_flag) == FR_FAIL)
                goto err;

            // 如果是压缩过的数据，必须要全部接收完再解析
            if (strcmp(arr_flag, "\x01") == 0)
                return APM_L7_ANALYZE_TODO;
        }
        else
            return APM_L7_ANALYZE_TODO;
    }
    else if (ui_len < ui_data_len - 4 || ui_data_len < SAP_HEAD_LEN)
        goto err;
    else
    {
        i_ret = bytebuff_add(p_st_fragment->p_st_data, p_data, ui_data_len);
        if (i_ret != FR_SUCC)
            goto err;
    }

    // 解析头部数据
    i_ret = sap_analysis_head(p_st_fragment->p_st_data, ui_len, &p_st_head);
    if (i_ret != FR_SUCC)
        goto err;

    if (p_st_private->p_st_head)
        frfree(p_st_private->p_st_head);
    p_st_private->p_st_head = p_st_head;
    p_st_fragment->u64_total_len = p_st_head->ul_packet_len;

    // 解析体数据
    i_ret = __sap_analysis_data(p_st_private, p_st_conn, p_st_hash_report, p_st_packet);
    if (i_ret == APM_L7_ANALYZE_FAIL)
        goto err;
    else if (i_ret == APM_L7_ANALYZE_TODO)
    {
        frfree(p_st_private->p_st_head);
        p_st_private->p_st_head = NULL;
        return APM_L7_ANALYZE_TODO;
    }
    else
    {
        frfree(p_st_private->p_st_head);
        p_st_private->p_st_head = NULL;
        if (p_st_fragment->p_st_data)
            bytebuff_free(&p_st_fragment->p_st_data);
        p_st_fragment->u64_total_len = 0;

        return i_ret;
    }

err:
    __sap_reset_private(p_st_private);
    return APM_L7_ANALYZE_FAIL;
}

/*!
 * 私有信息销毁
 *
 * \param *p_private_session        (void   SAP的私有session数据)
 *
 * \return FR_SUCC
 *
 */
int sap_session_destroy(void *p_private_session)
{
    L7session_sap_private *p_st_private;
    L7Session_sap *p_st_l7_session;

    // 判断session是否为空
    if (p_private_session == NULL)
        return FR_SUCC;

    p_st_private = (L7session_sap_private *)p_private_session;

    // 销毁分片包数据
    if (p_st_private->p_st_fragment)
    {
        // 销毁分片包内的packet数据
        __sap_init_fragment(p_st_private->p_st_fragment);
        frfree(p_st_private->p_st_fragment);
    }

    // 销毁头数据
    if (p_st_private->p_st_head)
        frfree(p_st_private->p_st_head);

    if (p_st_private->p_st_l7_session)
    {
        p_st_l7_session = p_st_private->p_st_l7_session;

        frfree(p_st_private->p_st_l7_session);
    }

    frreport_body_free(&p_st_private->p_st_data_req);
    frreport_body_free(&p_st_private->p_st_data_resp);

    frreport_body_l7list_free(&p_st_private->p_lst_req);

    frfree(p_st_private);

    return FR_SUCC;
}

/*!
 * 判断当前数据链路是否是sap协议
 *
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_packet         (Apm_packet         数据包信息)
 *
 * \return APM_L7_IS_NO   (NO)
 *         APM_L7_IS_YES  (YES)
 *
 */
int sap_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    char *p_payload = NULL;
    char arr_magic[3];
    unsigned int ui_len = 0;
    int i_ret = 0;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_packet->p_payload == NULL || p_st_packet->ui_payload_len < 20)
        return APM_L7_IS_NO;

    p_payload = p_st_packet->p_payload;
    ui_len = p_st_packet->ui_payload_len;

    // todo
    if (*(p_payload + 11) == 0x01)
    {
        snprintf(arr_magic, sizeof(arr_magic), "%s", p_payload + 17);
        if (strcmp(arr_magic, "\x1f\x9d") != 0)
            goto end;
    }
    else
        goto end;

    // 方向不明确
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        if (*(p_payload + 9) == 0)
        {
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            if (i_ret != FR_SUCC)
            {
                frdbg("frcap_set_cs_srv failed\n");
                return APM_L7_IS_NO;
            }
            frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
            p_st_conn->flg_direct_known = FR_DIRECT_KNOWN;
            return APM_L7_IS_YES;
        }
        else if (*(p_payload + 9) == 1)
        {
            i_ret = frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            if (i_ret != FR_SUCC)
            {
                frdbg("frcap_set_cs_srv failed\n");
                return APM_L7_IS_NO;
            }
            frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
            p_st_conn->flg_direct_known = FR_DIRECT_KNOWN;
            return APM_L7_IS_YES;
        }
    }

    return APM_L7_IS_YES;

end:
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*!
 * sap packet解析
 *
 * \param *p_st_conn           (Conntrack          连接信息)
 * \param *p_st_packet         (Apm_packet         数据包信息)
 * \param *p_st_hash_report    (Frhash_header      上报链表)
 *
 * \return APM_L7_ANALYZE_SUCC:成功\n
 *         APM_L7_ANALYZE_FAIL:失败\n
 *         APM_L7_ANALYZE_TODO:数据包不完整
 *
 */
int sap_analysis(Conntrack *p_st_conn
               , Apm_packet *p_st_packet
               , Frhash_header *p_st_hash_report)
{
    L7session_sap_private *p_st_private = NULL;
    L7_session *p_st_session = NULL;
    int i_ret = 0;

    if (p_st_conn == NULL || p_st_packet == NULL
         || p_st_hash_report == NULL)
         return APM_L7_ANALYZE_FAIL;

    // 到Conntrack中取得session信息
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    /*
    * 如果入力p_st_packet是FIN包, 说明本次SAP的connection结束,
    * 释放本次session信息. 如果入力p_st_packet是SYN包,说明新的SAP的
    * connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN
        || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        // 销毁所有相关本次SAP的connection的数据
        sap_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

     // 本次链路的第一个有效packet包,创建链路
    if (p_st_session->p_session_private == NULL)
    {
        // 初始化SAP的私有数据
        i_ret = __sap_init_private(p_st_session);
        if (i_ret != FR_SUCC)
            return APM_L7_ANALYZE_FAIL;

        // 设置session ID
        fruuid(p_st_session->arr_session_id);
    }

    p_st_private = (L7session_sap_private *)p_st_session->p_session_private;

    i_ret = __sap_getdata_analysis(p_st_private
                                  , p_st_conn
                                  , p_st_hash_report
                                  , p_st_packet
                                  , p_st_packet->p_payload
                                  , p_st_packet->ui_payload_len);
    return i_ret;
}
